﻿using Castle.Components.DictionaryAdapter.Xml;
using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static _06_AOP.BusinessLogic;
using static System.Net.Mime.MediaTypeNames;

namespace _06_AOP
{
    public class DynamicProxyExample
    {
        /// <summary>
        /// 代理任意标准
        /// </summary>
        public class ShareInterceptor1 : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                Console.WriteLine("Proxy1:已对接收方进行验证");
                invocation.Proceed();//执行下一个拦截器或者目标方法
                Console.WriteLine("Proxy1:已确认对方已经收到");
            }
        }
        /// <summary>
        /// 代理任意标准
        /// </summary>
        public class ShareInterceptor2 : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                Console.WriteLine("Proxy2:已开启加速通道");
                invocation.Proceed();//执行下一个拦截器或者目标方法
                Console.WriteLine("Proxy2:已关闭加速通道");
            }
        }
      
        public class Invocaltion : IInvocation
        {
            public object[] Arguments { get; set; }

            public Type[] GenericArguments { get; set; }

            public object InvocationTarget { get; set; }

            public MethodInfo Method { get; set; }

            public MethodInfo MethodInvocationTarget { get; set; }

            public object Proxy { get; set; }

            public object ReturnValue { get; set; }

            public Type TargetType { get; set; }

            public IInvocationProceedInfo CaptureProceedInfo()
            {
                throw new NotImplementedException();
            }

            public object GetArgumentValue(int index)
            {
                throw new NotImplementedException();
            }

            public MethodInfo GetConcreteMethod()
            {
                throw new NotImplementedException();
            }

            public MethodInfo GetConcreteMethodInvocationTarget()
            {
                throw new NotImplementedException();
            }

            public void Proceed()
            {
                Method.Invoke(Proxy, Arguments);
            }

            public void SetArgumentValue(int index, object value)
            {
                throw new NotImplementedException();
            }
        }
        public class CastelPhoneServiceProxy : IPhoneService
        {
            private IPhoneService _taget;
            private IInterceptor[] _interceptors;

            public CastelPhoneServiceProxy(IPhoneService taget, IInterceptor[] interceptors)
            {
                _taget = taget;
                _interceptors = interceptors;
            }

            public string Mobile { get => _taget.Mobile; set => _taget.Mobile = value; }
            public string Message { get => _taget.Message; set => _taget.Message = value; }

            public void Send()
            {
                var stack = new Stack<IInterceptor>(_interceptors.Reverse());
                if (stack.Any())
                {
                    var item = stack.Pop();
                    var invocation = GetNextInvocation(stack);
                    item.Intercept(invocation);
                }
                else
                {
                    _taget.Send();
                }
            }
            /// <summary>
            /// 递归获取Invocaltion
            /// </summary>
            /// <param name="stack"></param>
            /// <returns></returns>
            private IInvocation GetNextInvocation(Stack<IInterceptor> stack)
            {
                if (stack.Any())
                {
                    var next = stack.Pop();

                    return new Invocaltion
                    {
                        Arguments = new object[]
                        {
                            //递归
                            GetNextInvocation(stack)
                        },
                        Proxy = next,
                        Method = typeof(IInterceptor).GetMethod(nameof(IInterceptor.Intercept)) ?? throw new NullReferenceException()
                    };
                }
                else
                {
                    return new Invocaltion
                    {
                        Arguments = new object[]
                        {
                        },
                        Proxy = _taget,
                        Method = _taget.GetType().GetMethod(nameof(IPhoneService.Send)) ?? throw new NullReferenceException()
                    };
                }
            }
        }
    }

}